package com.yangzb;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang.StringUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HiveUtil {
    private static String JDBC_DRIVER_NAME = "";
    private static String CONNECTION_URL = null;
    private static String HIVE_JDBC_USER = "";
    private static String HIVE_JDBC_PWD = "";
    private static String HIVE_QUEUE_NAME = "";

    public static void init(Map<String, String> map) {
        JDBC_DRIVER_NAME = MapUtil.getStr(map,"spring.datasource.hive.driverClassName");
        CONNECTION_URL = MapUtil.getStr(map,"spring.datasource.hive.url");
        HIVE_JDBC_USER = MapUtil.getStr(map,"spring.datasource.hive.username");
        HIVE_JDBC_PWD = MapUtil.getStr(map,"spring.datasource.hive.password");
        HIVE_QUEUE_NAME = MapUtil.getStr(map,"spring.datasource.hive.queuename");
        try {
            Class.forName(JDBC_DRIVER_NAME);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("hive init error:" + e.getLocalizedMessage(), e);
        }
    }

    public static Connection getConnection(Map config) throws Exception {
        int curTimes = 1;
        Connection conn = null;
        Exception conEex = null;
        while (curTimes == 1 || (curTimes <= 3 && conEex != null)) {
            conEex = null;
            try {
                if (curTimes > 1) {
                    System.out.println("获取hive连接出现异常，开始重连：" + curTimes);
                }
                conn = DriverManager.getConnection(CONNECTION_URL, HIVE_JDBC_USER, HIVE_JDBC_PWD);
            } catch (Exception e) {
                System.out.println("获取hive连接出现异常：");
                e.printStackTrace();
                conEex = e;
            }
            curTimes++;
        }
        if (conEex != null) {
            throw new RuntimeException("获取hive连接重连3次后，出现异常", conEex);
        }
        return conn;
    }

    /**
     * existsTable
     *
     * @param tbName
     * @return
     */
    public static boolean existsTable(String tbName, Map config) {
        System.out.println("开始判断表是否存在" + tbName);
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        boolean flag = false;
        try {
            if (StringUtils.isNotEmpty(tbName)) {
                System.out.println("开始获取conn");
                conn = getConnection(config);
                 System.out.println("开始获取stmt");
                stmt = conn.createStatement();
                if (StrUtil.isNotBlank(HIVE_QUEUE_NAME)) {
                    String setQueueName = "set tez.queue.name=" + HIVE_QUEUE_NAME;
                     System.out.println("sql:" + setQueueName);
                    stmt.execute(setQueueName);
                     System.out.println("set success");
                }
                String queryString = "show tables like '" + tbName + "'";
                 System.out.println("开始执行sql" + queryString);
                rs = stmt.executeQuery(queryString);
                 System.out.println("执行sql完成");
                while (rs.next()) {
                    String name = rs.getString("tab_name");
                     System.out.println(name + "|" + tbName);
                    if (tbName.toLowerCase().equals(name.toLowerCase())) {
                        flag = true;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            flag = false;
            e.printStackTrace();
            throw new RuntimeException("判断hive表" + tbName + "是否存在出现异常:" + e.getLocalizedMessage(), e);
        } finally {
            close(rs);
            close(stmt);
            close(conn);
        }
        return flag;
    }

    public static List<HashMap> selectList(String sql, Map config, String... firstSql) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        List<HashMap> newList = new ArrayList<HashMap>();
        try {
            conn = getConnection(config);
            stmt = conn.createStatement();
            if (StrUtil.isNotBlank(HIVE_QUEUE_NAME)) {
                String setQueueName = "set tez.queue.name=" + HIVE_QUEUE_NAME;
                 System.out.println("sql:" + setQueueName);
                stmt.execute(setQueueName);
            }
            if (firstSql != null && firstSql.length > 0) {
                int size = firstSql.length;
                for (int i = 0; i < size; i++) {
                    String cmdSql = firstSql[i];
                    stmt.execute(cmdSql);
                }

            }
             System.out.println("set success");
            rs = stmt.executeQuery(sql);
            int count = rs.getMetaData().getColumnCount();
            while (rs.next()) {
                HashMap hmObj = new HashMap();
                for (int i = 1; i <= count; i++) {
                    hmObj.put(rs.getMetaData().getColumnName(i).replace("c_", ""), rs.getObject(i));
                }
                newList.add(hmObj);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("执行sql【" + sql + "】出现异常:" + e.getLocalizedMessage(), e);
        } finally {
            close(rs);
            close(stmt);
            close(conn);
        }
        return newList;
    }


    public static Boolean update(String sql, Map config, String... firstSql) {
        Connection conn = null;
        Statement stmt = null;
        Boolean rs = false;

         System.out.println("sql:" + sql);
        try {
            conn = getConnection(config);
            stmt = conn.createStatement();
            if (StrUtil.isNotBlank(HIVE_QUEUE_NAME)) {
                String setQueueName = "set tez.queue.name=" + HIVE_QUEUE_NAME;
                 System.out.println("setQueueName:" + setQueueName);
                stmt.execute(setQueueName);
                 System.out.println("set success");
            }
            if (firstSql != null && firstSql.length > 0) {
                int size = firstSql.length;
                for (int i = 0; i < size; i++) {
                    String cmdSql = firstSql[i];
                    stmt.execute(cmdSql);
                }

            }
            rs = stmt.execute(sql);
             System.out.println("rs:" + rs);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("执行sql【" + sql + "】出现异常:" + e.getLocalizedMessage(), e);
        } finally {
            close(stmt);
            close(conn);
        }
        return rs;
    }

    /**
     * 关闭conn
     *
     * @param conn
     */
    public static void close(Connection conn) {
        try {
            if (conn != null && !conn.isClosed()) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            conn = null;
        }
    }

    /**
     * 关闭Statement
     *
     * @param stmt
     */
    public static void close(Statement stmt) {
        try {
            if (stmt != null) {
                stmt.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            stmt = null;
        }

    }

    /**
     * 关闭PreparedStatement
     *
     * @param pst
     */
    public static void close(PreparedStatement pst) {
        try {
            if (pst != null) {
                pst.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            pst = null;
        }
    }

    /**
     * 关闭ResultSet
     *
     * @param rs
     */
    public static void close(ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            rs = null;
        }
    }

    /**
     * 关闭
     *
     * @param objs 可关闭的资源对象有
     *             Connection、
     *             Statement、
     *             PreparedStatement、
     *             ResultSet
     *             别的类型资源自动忽略
     */
    public static void closeAll(Object... objs) {
        for (Object obj : objs) {
            if (obj instanceof Connection) {
                close((Connection) obj);
            }
            if (obj instanceof Statement) {
                close((Statement) obj);
            }
            if (obj instanceof PreparedStatement) {
                close((PreparedStatement) obj);
            }
            if (obj instanceof ResultSet) {
                close((ResultSet) obj);
            }
        }
    }
}
